package org.onvivals.app.ai.llm.model.doubao;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.emoji.EmojiUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.vdurmont.emoji.EmojiParser;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.onvivals.app.ai.tts.TTSFactory;
import org.onvivals.app.mqtt.util.PlayUtil;
import org.onvivals.module.iot.entity.IotDevice;
import org.onvivals.module.iot.entity.IotMessageLog;
import org.onvivals.module.iot.service.IIotDeviceService;
import org.onvivals.module.iot.service.IIotMessageLogService;
import org.onvivals.module.pms.entity.PmsHistory;
import org.onvivals.module.pms.entity.PmsQuestionAnswer;
import org.onvivals.module.pms.entity.PmsRole;
import org.onvivals.module.pms.service.IPmsQuestionAnswerService;
import org.springframework.scheduling.annotation.Async;

import java.io.File;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 描述：CozeEventSourceListener
 *
 */
@Slf4j
public class DoubaoSSEEventSourceListener extends EventSourceListener {

    private static final Pattern SENTENCE_END_PATTERN = Pattern.compile("[。！？；?.!;]");
    private StringBuilder answer = new StringBuilder();
    private StringBuilder totalAnswer = new StringBuilder();
    private int count;
    private AtomicInteger index = new AtomicInteger(0);

    private String deviceNum;

    private String question;

    private PmsRole pmsRole;

	private static IPmsQuestionAnswerService questionAnswerService;

	private static IIotDeviceService iotDeviceService;

	static {
		questionAnswerService = SpringUtil.getBean(IPmsQuestionAnswerService.class);
		iotDeviceService = SpringUtil.getBean(IIotDeviceService.class);
	}


    public DoubaoSSEEventSourceListener(PmsRole pmsRole, String deviceNum, String question) {
        this.pmsRole = pmsRole;
        this.deviceNum = deviceNum;
        this.question = question;
		this.count = 5;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onOpen(EventSource eventSource, Response response) {
        log.info("======== Doubao 对话开始 ========");
    }

    /**
     * {@inheritDoc}
     */
    @SneakyThrows
    @Override
    public void onEvent(EventSource eventSource, String id, String type, String data) {
        if (StrUtil.equals("[DONE]", data) || !JSONUtil.isTypeJSON(data)) {
			String content;
			content = EmojiUtil.removeAllEmojis(answer.toString());
            if (StrUtil.isNotEmpty(content)) {
                log.info("结束数据：{} 序号:{}", answer, index);
                pushMessage(content, index.get());
                answer.setLength(0);
            }
            log.info("======== 对话结束 ========");
        }
        if (JSONUtil.isTypeJSONObject(data)) {
            Optional<Object> o = Optional.of(JSONUtil.parseObj(data))
                    .map(x -> x.getJSONArray("choices"))
                    .filter(CollUtil::isNotEmpty)
                    .map(x -> (JSONObject) x.get(0))
                    .map(x -> x.getJSONObject("delta"))
                    .map(x -> x.getStr("content"));
           Object content = o.orElseGet(() -> "");
		   //过滤表情符号
			content = EmojiParser.removeAllEmojis(content.toString());

            if (ObjectUtil.isNotEmpty(content)) {
                answer.append(content);
                totalAnswer.append(content);
                Matcher matcher = SENTENCE_END_PATTERN.matcher(answer.toString());
                int lastMatchPosition = -1;
                while (matcher.find()) {
                    lastMatchPosition = matcher.end();
                }
                if (lastMatchPosition != -1) {
                    if (lastMatchPosition >= count) {
                        String message = answer.substring(0, lastMatchPosition);
                        log.info("数据：{} 序号:{}", message, index.get());
                        pushMessage(message, index.get());
                        answer.delete(0, lastMatchPosition);
                        count = Math.min(count + 5, 80);
                        index.incrementAndGet();
                    }
                }
            }
        }
    }

    @Override
    public void onClosed(EventSource eventSource) {
        PmsHistory userHistoryAssistant = new PmsHistory();
        userHistoryAssistant.setRole("assistant");
        userHistoryAssistant.setContent(totalAnswer.toString());
        userHistoryAssistant.setDeviceId(deviceNum);
        userHistoryAssistant.insert();

        //查询用户记录
        PmsHistory userHistory = new PmsHistory();
        userHistory.setRole("user");
        userHistory.setContent(question);
        userHistory.setDeviceId(deviceNum);
        userHistory.insert();

		log.info("整体回答为：{}", totalAnswer.toString());
		PmsQuestionAnswer questionAnswer = new PmsQuestionAnswer();
		IotDevice iotDevice = iotDeviceService.selectDeviceBySerialNumber(deviceNum);
		questionAnswer.setUid(iotDevice.getUserId());
		questionAnswer.setDeviceNum(deviceNum);
		questionAnswer.setAnswer(totalAnswer.toString());
		questionAnswer.setQuestion(question);
		questionAnswerService.saveOrUpdate(questionAnswer);

    }

    @SneakyThrows
    @Override
    public void onFailure(EventSource eventSource, Throwable t, Response response) {
        if (Objects.isNull(response)) {
            return;
        }
        ResponseBody body = response.body();
        if (Objects.nonNull(body)) {
            log.error("Doubao  sse连接异常data：{}，异常：{}", body.string(), t);
        } else {
            log.error("Doubao  sse连接异常data：{}，异常：{}", response, t);
        }
        eventSource.cancel();
    }

    public void pushMessage(String answer, int index) {
        try {
			answer = answer.replaceAll("[\\(（][^\\)）]*[\\)）]", "");
            Optional<String> optionalString = Objects.requireNonNull(TTSFactory.build(pmsRole)).speechSynthesizer(deviceNum, answer);
            if (optionalString.isPresent()) {
                String url = "";
                //判断optionalString 是否是http或者https
                if (optionalString.get().startsWith("http") || optionalString.get().startsWith("https")) {
                    url = optionalString.get();
                } else {
                    FileStorageService fileStorageService = SpringUtil.getBean(FileStorageService.class);
                    File file1 = new File(optionalString.get());
                    String[] originalFilename = file1.getName().split("\\.");
                    String dateStr = DateUtil.today();
                    String path = dateStr + "/";
                    String fileName = originalFilename[0] + "-" + IdUtil.simpleUUID() + StrUtil.DOT + FileUtil.extName(file1.getName());
                    String objectName = path + fileName;
                    FileInfo upload = fileStorageService.of(file1, objectName, "audio/mp3").upload();
                    url = upload.getUrl();
                }
                log.info("语音合成成功：{}", url);
                if (index == 0 ){
                    PlayUtil playUtil = SpringUtil.getBean(PlayUtil.class);
                    //todo 开始推送
                    playUtil.play(deviceNum, url, "", index);
					saveInfo(url,index,answer,deviceNum);
                }else {
                    saveInfo(url,index,answer,deviceNum);
                }
            }
        } catch (Exception e) {
            log.error("Doubao 推送消息异常：{}", e.getMessage());
        }

    }

    @Async
    public void saveInfo(String url,int index,String answer,String deviceNum) {
                IIotMessageLogService iotMessageLogService = SpringUtil.getBean(IIotMessageLogService.class);
                iotMessageLogService.remove(Wrappers.<IotMessageLog>lambdaQuery().eq(IotMessageLog::getDeviceId, deviceNum).ge(IotMessageLog::getSortNum, index));
                IotMessageLog messageLog = new IotMessageLog();
                messageLog.setDeviceId(deviceNum);
                messageLog.setMessageUrl(url);
                messageLog.setSortNum(index);
                messageLog.setMessageContent(answer);
                messageLog.insert();
    }


}
